package sample.view;

import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Worker;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import javafx.util.Callback;
import javafx.util.StringConverter;
import sample.crawler.LogTask;
import sample.crawler.base.BaseTask;
import sample.crawler.base.TaskFactory;
import sample.enums.MapType;
import sample.model.Address;
import sample.model.Company;
import sample.model.Log;
import sample.utils.*;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class MainController extends LogUtils {

    @FXML
    private VBox statusPanel;
    @FXML
    public TextField keywords;
    @FXML
    public TextField exclusiveWords;
    @FXML
    public CheckBox filterTel;
    @FXML
    public TableView<Company> qrTable;
    @FXML
    private TableColumn<Company, String> index;
    @FXML
    private TableColumn<Company, String> tel;
    @FXML
    private TableColumn<Company, String> name;
    @FXML
    private TableColumn<Company, String> area;
    @FXML
    private TableColumn<Company, String> address;
    @FXML
    private TableColumn<Company, String> industry;
    @FXML
    private TableColumn<Company, String> keyword;
    @FXML
    private TableColumn<Company, String> source;
    @FXML
    private TableColumn<Company, String> coordinate;
    @FXML
    private Separator seperator;
    @FXML
    private ComboBox<Address> province;
    @FXML
    private ComboBox<Address> city;
    @FXML
    private ComboBox<Address> district;
    @FXML
    private Button stop;
    @FXML
    private Button clear;
    @FXML
    private Button start;
    @FXML
    private Button export;
    @FXML
    private HBox mapContainer;

    private List<CheckBox> mapList = Lists.newArrayList();

    /**
     * 渲染视图
     */
    private void renderView(){
        index.prefWidthProperty().bind(qrTable.widthProperty().multiply(0.05));

        // 渲染地图选择
        MapType.list.forEach(x->{
            CheckBox map = new CheckBox(x.getDesc());
            map.setId(x.getCode());
            mapList.add(map);
            mapContainer.getChildren().add(map);
        });

        CheckBox selectAll = new CheckBox("全选");
        selectAll.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {

                boolean selected = selectAll.getText().equals("全选");
                mapList.stream().forEach(x->{
                    x.setSelected(selected);
                });
                selectAll.setText(selected ? "反选" : "全选");
            }
        });
        mapContainer.getChildren().add(selectAll);

    }


    /**
     * 初始化地址下拉框
     */
    private void initAddressComboBox(){
        province.setItems(FXCollections.observableArrayList(AddressUtils.getAddress(null)));
        province.getSelectionModel().select(0);

        city.setItems(FXCollections.observableArrayList(AddressUtils.getAddress(province.getValue().getCode())));
        city.getSelectionModel().select(0);

        district.setItems(FXCollections.observableArrayList(AddressUtils.getAddress(city.getValue().getCode())));
        district.getSelectionModel().select(0);


        Callback<ListView<Address>, ListCell<Address>> cellFactoryCallback = new Callback<ListView<Address>, ListCell<Address>>() {
            @Override
            public ListCell<Address> call(ListView<Address> param) {
                final ListCell<Address> cell = new ListCell<Address>() {

                    @Override
                    protected void updateItem(Address t, boolean bln) {
                        super.updateItem(t, bln);

                        if (t != null) {
                            setText(t.getName());
                        } else {
                            setText(null);
                        }
                    }

                };
                return cell;
            }
        };
        province.setCellFactory(cellFactoryCallback);
        city.setCellFactory(cellFactoryCallback);
        district.setCellFactory(cellFactoryCallback);


        province.valueProperty().addListener((obs, oldVal, newVal) -> {
            System.out.println("province:"+oldVal+"->"+newVal);
            if(newVal == null) return;
            String selectCode = newVal.getCode();

            ObservableList<Address> cityList = FXCollections.observableArrayList(AddressUtils.getAddress(selectCode));
            city.setItems(cityList);
            city.getSelectionModel().select(0);

        });


        city.valueProperty().addListener((obs, oldVal, newVal) -> {
            System.out.println("city:"+oldVal+"->"+newVal);
            if(newVal == null) return;
            String selectCode = newVal.getCode();

            ObservableList<Address> dList = FXCollections.observableArrayList(AddressUtils.getAddress(selectCode));
            district.setItems(dList);
            district.getSelectionModel().select(0);

        });

        StringConverter<Address> stringConverter = new StringConverter<Address>() {
            @Override
            public String toString(Address object) {
                return object == null ? null : object.getName();
            }

            @Override
            public Address fromString(String string) {
                return JSONObject.parseObject(string, Address.class);
            }
        };
        province.setConverter(stringConverter);
        city.setConverter(stringConverter);
        district.setConverter(stringConverter);

    }

    private void initTableColumn(){
        index.setCellValueFactory(cellData -> cellData.getValue().indexProperty());
        tel.setCellValueFactory(cellData -> cellData.getValue().telProperty());
        name.setCellValueFactory(cellData -> cellData.getValue().nameProperty());
        area.setCellValueFactory(cellData -> cellData.getValue().districtProperty());
        address.setCellValueFactory(cellData -> cellData.getValue().addressProperty());
        industry.setCellValueFactory(cellData -> cellData.getValue().industryProperty());
        keyword.setCellValueFactory(cellData -> cellData.getValue().keywordProperty());
        source.setCellValueFactory(cellData -> cellData.getValue().sourceProperty());
        coordinate.setCellValueFactory(cellData -> cellData.getValue().coordinateProperty());
    }

    @FXML
    private void initialize() {

        this.renderView();

        this.initAddressComboBox();

        this.initTableColumn();

        //Login.mainStage.setAlwaysOnTop(true);
    }

    public void initMap(Map<String, Object> mapUrl){
        TaskFactory.init(mapUrl);
    }



    private boolean checkCheckBox()
    {

        long selectCount = mapList.stream().filter(x->x.isSelected()).count();
        if(selectCount < 1) {
            AlertUtils.alert("未选择电子地图","请选择一个电子地图", Login.mainStage);
            return false;
        }

        return true;
    }

    private boolean validateParam(String area){
        if(!checkCheckBox())
        {
            return false;
        }

        if(keywords.getText().trim().equals(""))
        {
            AlertUtils.alert("未输入行业关键词","请输入行业关键词",  Login.mainStage);
            return false;
        }

        if(area == null) {
            AlertUtils.alert("未选择区域","请选择区域",  Login.mainStage);
            return false;
        }
        return true;
    }

    @FXML
    public void handleStart(){
        String p = province.getValue() == null ? "" : province.getValue().getName();
        String c = city.getValue() == null ? "" : city.getValue().getName();
        String d = district.getValue() == null ? "" : district.getValue().getName();

        StringBuffer area = new StringBuffer()
                .append(p).append(",")
                .append(c).append(",")
                .append(d);
        // 验证参数
        boolean validate = validateParam(area.toString());
        if(!validate) return;

        // 清除
        this.handleClear();

        // 禁用开始 清空 导出
        disabledButtons();

        // 异步执行任务
        List<BaseTask> all = execTask(area.toString());

        // stop按钮添加事件，取消正在执行的任务
        stop.setOnAction(new EventHandler<ActionEvent>(){
            @Override
            public void handle(ActionEvent e){
                //task.cancel();
                for (BaseTask task : all) {
                    task.cancel(true);
                }
            }
        });

        // 任务状态监听，成功、取消、失败将禁用按钮恢复
        for (BaseTask task:all) {
            task.stateProperty().addListener(new ChangeListener<Worker.State>() {
                @Override
                public void changed(ObservableValue<? extends Worker.State> observable, Worker.State oldValue, Worker.State newValue) {
                    if(newValue == Worker.State.SUCCEEDED || newValue == Worker.State.CANCELLED || newValue == Worker.State.FAILED){
                        task.setStop(true);
                    }
                    long stopCount = all.stream().filter(x->x.getStop() != null && x.getStop()).count();
                    if(stopCount == 0) {
                        start.setDisable(false);
                        clear.setDisable(false);
                        stop.setDisable(false);
                    }
                }
            });
        }

        // 将搜索地区关键字发往服务器
        Log log = new Log(LoginController.uid, keywords.getText(), exclusiveWords.getText(), p, c, d, (filterTel.isSelected() ? 1 : 0));
        //new LogTask(log).run();
        //new Thread(new LogTask(log)).start();
        Platform.runLater(new LogTask(log));

    }


    private void disabledButtons(){
        start.setDisable(true);
        clear.setDisable(true);
        export.setDisable(true);
    }

    /**
     * 执行任务
     * @return
     */
    private List<BaseTask> execTask(String area){
        List<BaseTask> all = Lists.newArrayList();
        String[] keyArr = keywords.getText().split(" ");
        List<String> exclusiveWordsList = null;
        if(exclusiveWords != null && !exclusiveWords.getText().trim().equals("")) {
            exclusiveWordsList = Stream.of(exclusiveWords.getText().split(" ")).filter(x-> !StringUtils.isEmpty(x.trim())).collect(Collectors.toList());
        }

        for (String key : keyArr) {
            for (CheckBox map : mapList) {
                if (map.isSelected()) {
                    runTask(map.getId(), key, area, exclusiveWordsList, all);
                }
            }
        }
        return all;
    }

    private void runTask(String map, String key, String area, List<String> exclusiveWordsList, List<BaseTask> all){
        BaseTask task = TaskFactory.getTask(map);
        task.bindTableView(qrTable);
        task.setQueryCondition(key, exclusiveWordsList, area, filterTel.isSelected());
        task.start();

        all.add(task);

        Label status = new Label();
        status.setTextFill(Color.RED);
        status.textProperty().bind(task.messageProperty());
        statusPanel.getChildren().add(status);


    }

    @FXML
    public void handleClear(){
        //keywords.clear();
        // 初始化编号
        IndexUtils.initIndex();
        // 清除状态栏
        statusPanel.getChildren().clear();
        // 清除table
        qrTable.setItems(FXCollections.observableArrayList());
    }

    @FXML
    public void handleExport(){
        FileChooser fileChooser = new FileChooser();
        FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter("Excel (*.xlsx)", "*.xlsx");
        fileChooser.getExtensionFilters().add(extFilter);
        Stage s = new Stage();
        File file = fileChooser.showSaveDialog(s);
        if (file == null)
            return;
        if(file.exists()){//文件已存在，则删除覆盖文件
            file.delete();
        }
        String exportFilePath = file.getAbsolutePath();

        ObservableList<Company> items = qrTable.getItems();
        List<String> list = new ArrayList<>(items.size()+1);
        list.add("来源,关键词,名称,联系电话,省市区,详细地址,类型,坐标");
        items.forEach(x->{
            list.add(x.getSource()+"\t"+x.getKeyword()+"\t"+x.getName()+"\t"+x.getTel()+"\t"+x.getDistrict()+"\t"+x.getAddress()+"\t"+x.getIndustry()+"\t"+x.getCoordinate());
        });
        try {
            ExcelUtil.writeExcel(exportFilePath, list);
        } catch (IOException e) {
            e.printStackTrace();
        }

        AlertUtils.alert("提示", "导出成功!\n保存路径:"+exportFilePath,  Login.mainStage);
    }

}
